#' Translate identifiers
#'
#' \code{trans} translates a vector of identifiers from one format to
#' another according to a given translation table (\emph{e.g.},
#' translating question IDs to question name).
#'
#' @param v Vector of any type.
#' @param to Character. Corresponding identifier format to translate
#'     our vector \code{v} to.
#' @param ttable Translation table. Must be a \code{data.frame}
#'     containing the columns specified by \code{to} and \code{by}
#' @param by Character. Column key for translation.
#'
#' @section Warning: This function is meant to serve as a constructor
#'     for identifier specific translation functions --- for example,
#'     see the function \code{\link{to_qids}}. It's not
#'     particularly useful or inuitive for direct use.
#'
#' @examples
#' \dontrun{
#' # Given a vector of question IDs saved to qids and we want the
#' # corresponding tag names using the translation table `qtable`.
#' trans(qids, to = "name", ttable = qtable, by = "question_id")
#' }
#'
#' @family translation helper functions
#' @seealso \code{\link{to_qids}} for question IDs,
#'     \code{\link{to_qnames}} for question names,
#'     \code{\link{to_cids}} for country IDs, \code{\link{to_cnames}}
#'     for country names.
#'
#' @export
trans <- function(v, to = NULL, ttable = NULL, by = NULL) {
    for (x in c("to", "ttable", "by"))
        if (is.null(eval(substitute(x))))
            stop("Missing argument: " %^% x)

    columns <- colnames(ttable)
    if (!by %in% columns | !to %in% columns)
        stop("Missing `to` or `by` column in translation table")

    if (any(!v %in% ttable[[by]]))
        stop("Missing values in ttable from " %^% deparse(substitute(v)))

    ttable[[to]][match(v, ttable[[by]])]
}

#' Translation helper functions
#'
#' Convenience functions to translate several common identifiers at V-Dem.
#'
#' @param v \code{CharacterVector} or \code{NumericVector}
#' @param ttable Translation table. See \link{trans}.
#'
#' @details The listed helper functions are fairly rigid in their
#'     assumptions, especially in the case of assumed column names in
#'     the translation table.
#'
#'     It's worth noting that the function \code{to_qlabels} expects
#'     not the \code{question} table as \code{ttable}, but rather the
#'     \code{codebook} table, which contains the canonical short-form
#'     question description texts. Further, it includes a call to
#'     \code{\link{get_root}} so that it can conveniently be called on
#'     the columns of the final dataset.
#'
#' @examples
#' \dontrun{
#' tags <- c("v2clacfree", "v2elpaidig")
#' qids <- to_qids(tags, qtable)
#' to_qnames(qids)
#' }
#'
#' @seealso \code{\link{trans}}
#' @name trans_helpers
NULL

#' @describeIn trans_helpers Translate country text IDs to country IDs
#' @export
to_cids <- function(v, ttable) {
    trans(v, to = "country_id", ttable = ttable, by = "country_text_id")
}

#' @describeIn trans_helpers Translate country text IDS to country names
#' @export
to_cnames <- function(v, ttable) {
    trans(v, to = "name", ttable = ttable, by = "country_text_id")
}

#' @describeIn trans_helpers Translate country IDs to country text IDs
#' @export
to_ctext_ids <- function(v, ttable) {
    trans(v, to = "country_text_id", ttable = ttable, by = "country_id")
}

#' @describeIn trans_helpers Translate question tag names to question IDs
#' @export
to_qids <- function(v, ttable) {
    trans(v, to = "question_id", ttable = ttable, by = "name")
}

#' @describeIn trans_helpers Translate question IDs to question tag names
#' @export
to_qnames <- function(v, ttable) {
    trans(v, to = "name", ttable = ttable, by = "question_id")
}

#' @describeIn trans_helpers Translate question tag names to question labels
#' @export
to_qlabels <- function(v, ttable) {
    # We call this function with the columns of a data.frame, so strip
    # out all the generated codelow/high, sd, mean etc etc.
    basetags <- get_root(v)

    # Unlike to_qids and to_qnames, some of our tag names may not be
    # in our lookup table. Instead of erroring, just return an empty
    # string unless it's historical in which case try the v2 form.
    basetags <- ifelse(is.hist(basetags) & !basetags %in% ttable$name,
                      "v2" %^% substring(basetags, 3),
                      basetags)

    out <- character(length(v))
    out[basetags %in% ttable$name] <- trans(basetags[basetags %in% ttable$name],
                                           to = "label", ttable = ttable, by = "name")

    out[is.na(out)] <- ""
    out
}
